import Dep from "./observer/dep";
import observer from "./observer/index";
import Watcher from './observer/watcher'

export default function initState(vm) {
    const opts = vm.$options
    if (opts.data) {
        initData(vm)
    }
    if (opts.computed) {
        initComputed(vm)
    }
    if (opts.watch) {
        initWatch(vm)
    }
}


function proxy(vm, target, key) {
    Object.defineProperty(vm, key, {
        get: function () {
            return vm[target][key]
        },
        set: function (newValue) {
            vm[target][key] = newValue
        },
    })
}

function initData(vm) { // 初始化data
    let data = vm.$options.data
    data = typeof vm.$options.data === 'function' ? data.call(vm) : data
    vm._data = data

    observer(data)

    for (let key in data) {
        proxy(vm, '_data', key)
    }

}

function initComputed(vm) {  // 计算属性初始化
    let computed = vm.$options.computed
    let watchers = vm.$watchers = {}
    for (let key in computed) {// 此时computed[key]就是用户的自定义的fn
        watchers[key] = new Watcher(vm, computed[key], { lazy: true })
        defineComputed(vm, key, computed[key])
    }

}

function defineComputed(target, key, comInfo) {
    let setter = comInfo.set || (() => { })
    Object.defineProperty(target, key, {
        get: computedGetter.call(target, key),
        set: setter
    })
}


// computerWatcher 自身不收集渲染watcher 而是收集dep上对应的渲染watcher 
function computedGetter(key) {
    return function () {
        let watcher = this.$watchers[key]  // 当前的watcher
        if (watcher) {
            if (watcher.flag) { // 如果是第一次执行
                watcher.evaluate()
            }

            if (Dep.target) { // 此时的dep.target就是渲染watcher
                watcher.depend()
            }
            return watcher.value
        }

    }
}

function initWatch(vm) {
    let watch = vm.$options.watch
    for (let key in watch) {
        if (Array.isArray(watch[key])) {
            for (let i = 0; i < watch[key].length; i++) {
                createWatcher(vm, key, watch[key][i])
            }
        } else {
            createWatcher(vm, key, watch[key])
        }

    }
}

function createWatcher(vm, key, handle, options) {
    if (typeof handle === 'object') {
        options = handle
        handle = handle.handler;
    }

    if (typeof handle === 'string') {
        handle = vm[handle]
    }
    return vm.$watch(key, handle)
}